#!/bin/dash
#
#    Copyright (C) 2009-2013  Vitaly Druzhinin
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# setup global variables
# BEGIN SECTION

# Set path to flex firewall etc directory
if test -z "$flexfw_ETC_DIR"
then
    flexfw_ETC_DIR=/etc/flex-fw
fi


# Set path to flex firewall lib directory
if test -z "$flexfw_LIB_DIR"
then
    flexfw_LIB_DIR=/usr/lib/flex-fw
fi


# Get profile name
# !!! More info about network profiling look at http://etcnet.org/ !!!
# 1. Try get profile from env.
if test ! -z "$NETPROFILE"
then
    flexfw_PROFILE=$NETPROFILE
else

    # 2. Try get profile from flex-fw configuration.
    if test -e $flexfw_ETC_DIR/profile
    then
        flexfw_PROFILE=`cut -d " " -f 1 $flexfw_ETC_DIR/profile`
    else

        # 2. Try get profile from Linux kernel parameters.
        for KERNEL_PARAM in `cat /proc/cmdline`
        do
            if test "netprofile" = `echo $KERNEL_PARAM | cut -d "=" -f 1`
            then
                flexfw_PROFILE=`echo $KERNEL_PARAM | cut -d "=" -f 2`
            fi
        done

    fi # test -e $flexfw_ETC_DIR/profile

fi # test ! -z "$NETPROFILE"


#
# setup global variables
# END SECTION
#

#
# function flexfw_SetModiuleFlag
# Parameters:
# $1 - Name of module
# Purpose:
# Set variable with special name, which depend from module name
#
flexfw_SetModuleFlag () {

    #
    # if no parameters - do nothing
    #
    if test 0 -eq $#
    then
        return 1
    fi

    eval `echo "flexfw_module_$1=1" | tr "/.-" "_"`
    return 0

} # flexfw_SetModuleFlag ()


#
# function flexfw_TestModiuleFlag
# Parameters:
# $1 - Name of module for test
# Purpose:
# Exam existense variable with special name, which depend from module name
#
flexfw_TestModuleFlag () {

    #
    # if no parameters - do nothing
    #
    if test 0 -eq $#
    then
        return 1
    fi

    eval `echo "test \"\\\$flexfw_module_$1\"" | tr "/.-" "_"`
    return $?

} # flexfw_TestModuleFlag ()


#
# function require
# Parameters:
# $1   - Name of module or modules directory
# [$2] - Name of module or modules directory
# ...
# Purpose:
# Load modules
#
require () {

    #
    # local variables
    #
    local ModuleName    # module filename
    local ModulePath    # module pathname (dirname + filename)
    local ModulesList   # list of modules inside dir
    local OneModule     # one module name from list
    local Ret

    Ret=0

    # if no parameters - do nothing, return from function
    if test 0 -eq $#
    then
        return 1
    fi

    # Repeat for each parameter (module name)
    for ModuleName in $@
    do

        # Compose full module name (first variant)
        ModulePath=$flexfw_ETC_DIR/$ModuleName

        if test ! -e $ModulePath
        then

            # Check another directory (second variant)
            ModulePath=$flexfw_LIB_DIR/$ModuleName

            if test ! -e $ModulePath
            then
                return 1
            fi
        fi

        # If module is a file - run it!
        if test -f $ModulePath
        then

            # if module already loaded - skip another load
            flexfw_TestModuleFlag $ModulePath
            if test 0 -eq $?
            then
                continue
            fi

            # Run profiled module if exist else run ordinary module
            if test ! -z "$flexfw_PROFILE" -a -f $ModulePath#$flexfw_PROFILE
            then
                . $ModulePath#$flexfw_PROFILE
            else
                . $ModulePath
            fi

            Ret=$?
            if test 0 -eq $Ret
            then
                flexfw_SetModuleFlag $ModulePath
                continue
            else
                return $Ret
            fi

            continue

        fi # if test -f $ModulePath


        # If module is a directory - precess it!
        if test -d $ModulePath
        then

            # get list of modules inside (skip profiled)
            ModulesList=`ls --ignore "*#*" $ModulePath`

            if test "$ModulesList"              # if list non zero length
            then

                # run each module from list
                for OneModule in $ModulesList
                do

                    require $ModuleName/$OneModule

                done # for OneModule in $ModulesList
            fi # if test "$ModulesList"
        else

            # This name is not file, is not dir...
            Ret=1

        fi # if test -d $ModulePath

    done # for ModuleName in $@

} # require ()


#
# function flexfw_Execute
# Parameters: executed command
#
flexfw_Execute () {

    local TmpFile
    local Ret
    local Executed
    local Flock

    # If debug mode - print executed command at loggger
    if test "1" = "$flexfw_DEBUG"
    then
        echo "DEBUG: execute '$@'" | $flexfw_LOGGER
    fi

    #
    # If "No real Exec" mode - return
    #
    if test "1" = "$flexfw_NO_EXEC"
    then
        return 0
    fi # if test "1" = "$flexfw_NO_EXEC"

    #
    # Make command line for execute
    #
    Executed="$@"

    #
    # Use flock if defined
    #
    if test -n "$flexfw_FLOCK"
    then
        #
        # Use flock if defined
        #
        Flock="$flexfw_FLOCK -w $flexfw_FLOCK_TIMEOUT $flexfw_FLOCK_FILE"
    fi

    #
    # try make temporary file
    #
    TmpFile=`$flexfw_MKTEMP`
    if test 0 -eq $?
    then
        #
        # out STDERR to temporary file
        #
        $Flock $@ 2> $TmpFile
        Ret=$?
        if test 0 -ne $Ret
        then
            echo "Got a code=$Ret after executing '$Executed'" | $flexfw_LOGGER
        fi
        cat $TmpFile | $flexfw_LOGGER
        rm $TmpFile
        return $Ret
    else
        $Flock $@
        return $?
    fi

} # flexfw_Execute ()


#
# function is_ipv4
# Parameters: word
#
is_ipv4 () {
    if test "1" -eq `echo $1 | egrep -c '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?$'`
        then
            return 0
    fi
    return 1
}

#
# function create_zones 
# Parameters: no 
#
create_zones () {

    local tmp_fname
    local rc
    local ifname
    local addr

    # clear all previous definitions
    rm -f $flexfw_TMP_ZONES_DIR/*

    for file in `ls $flexfw_ZONES_DIR | grep -v '^!'`
    do
        tmp_fname=$flexfw_TMP_ZONES_DIR/`basename $file`
        >$tmp_fname
        if test "$?" -ne "0"
        then
            return $?
        fi
        while IFS=$'\n' read -r ITEM || test -n "$ITEM"
        do
            # line with comment
            rc=`echo $ITEM | grep -c '^#'`
            if test $rc -gt 0; then continue; fi
            ifname=`echo $ITEM | cut -d ' ' -f 1`
            addr=`echo $ITEM | cut -d ' ' -f 2`
            echo "$ifname $addr" >> $tmp_fname
        done < $flexfw_ZONES_DIR/$file
    done

    return $?
} # create_zones ()


#
# function flexfw_Execute_Std
# Parameters: litimed only by shell 
#
flexfw_Execute_Std () {
    if test "$#" -eq "0"
    then
        flexfw_Execute $flexfw_IPTABLES $flexfw_iptables_table \
           $flexfw_iptables_command \
           $flexfw_iptables_chain \
           $flexfw_iptables_rulenum \
           $flexfw_iptables_state \
           $flexfw_iptables_inif \
           $flexfw_iptables_outif \
           $flexfw_iptables_src \
           $flexfw_iptables_dst \
           $flexfw_iptables_proto \
           $flexfw_iptables_sport \
           $flexfw_iptables_dport \
           $flexfw_iptables_target
    else
        flexfw_Execute $flexfw_IPTABLES $flexfw_iptables_table \
           $flexfw_iptables_command \
           $flexfw_iptables_chain \
           $flexfw_iptables_rulenum \
           $flexfw_iptables_state \
           $flexfw_iptables_inif \
           $flexfw_iptables_outif \
           $flexfw_iptables_src \
           $flexfw_iptables_dst \
           $flexfw_iptables_proto \
           $flexfw_iptables_sport \
           $flexfw_iptables_dport \
           $flexfw_iptables_target \
           $@
    fi 
}


#
# function flexfw_Execute_Zone 
# Parameters: source zone, destination zone (optional),
# other iptables parameters
#
flexfw_Execute_Zone () {

    local source_zone
    local destination_zone
    local source_zone_file
    local destination_zone_file
    local direction_a
    local direction_b
    local file_a
    local file_b

    source_zone=$1
    destination_zone=$2
    source_zone_file="$flexfw_TMP_ZONES_DIR/$source_zone"
    destination_zone_file="$flexfw_TMP_ZONES_DIR/$destination_zone"

    shift 2

    #with zones: execute commands in loops for src and dst
    if test ! "$source_zone" = "any"
    then
       direction_a="src"
       file_a="$source_zone_file"
       if test ! "$destination_zone" = "any"
       then
           direction_b="dst"
           file_b="$destination_zone_file"
       fi
    else
       direction_a="dst"
       file_a="$destination_zone_file"
    fi

    while read if_a ip_a
    do
        if test "$direction_a" = "src"
        then
            flexfw_iptables_inif=""
            flexfw_iptables_src=""
            if test "$if_a" != "any"
            then
                flexfw_iptables_inif="--in-interface $if_a"
            fi
            if test "$ip_a" != "any"
            then
                flexfw_iptables_src="--source $ip_a"
            fi
        else
            flexfw_iptables_outif=""
            flexfw_iptables_dst=""
            if test "$if_a" != "any"
            then
                flexfw_iptables_outif="--out-interface $if_a"
            fi
            if test "$ip_a" != "any"
            then
                flexfw_iptables_dst="--destination $ip_a"
            fi
        fi

        if test ! -z "$direction_b"
        then
            while read if_b ip_b
            do
                flexfw_iptables_outif=""
                flexfw_iptables_dst=""
                if test "$if_b" != "any"
                then
                    flexfw_iptables_outif="--out-interface $if_b"
                fi
                if test "$ip_b" != "any"
                then
                    flexfw_iptables_dst="--destination $ip_b"
                fi
                flexfw_Execute_Std $*
            done < $file_b
        else
            flexfw_Execute_Std $@
        fi
    done < $file_a

} # flexfw_Execute_Zone

#
# setup global variables (continue)
# BEGIN SECTION
#

require vars/base

if test -z "$flexfw_DEFAULT_ACTION"
then
    flexfw_ACTION=$flexfw_DEFAULT_ACTION
else
    flexfw_ACTION="append"
fi

#
# setup global variables (continue)
# END SECTION
#

# end of file
